/*
 * 用户信息管理模块 V 0.1
 * 添加用户信息，取出用户信息，重设用户信息
 * 作者:basncy c@basncy.com
 */

#include "usbctrl.h"
#include "../include/clientinfo.h"
#include <pthread.h>

static pthread_rwlock_t	 cihrwlock = PTHREAD_RWLOCK_INITIALIZER;	//静态分配的，用PTHREAD_RWLOCK_INITIALIZER初始化
static struct ciheader  *cihptr;
static FILE		*cihfp;
static size_t		 cisize		   = sizeof(struct clientinfo);
//static pthread_rwlock_t cihrwlock;


/*
 * 初始化用户信息
 * 返回 0成功  -1失败
 */
int
initci()
{
  struct ciheader	cihdata;
  /* 初始化计划任务数据 */
  size_t cihsize=sizeof(struct ciheader);

  if((cihfp=fopen("clientinfo.data","r+")) == NULL){
    printf("文件不存在，使用初始化数据\n");
    cihfp=fopen("clientinfo.data","a+");
    memset(&cihdata, 0,cihsize);
  }
  else{
    printf("从文件中载入数据\n");
    fread(&cihdata,cihsize,1,cihfp);
  }
  printf("映射到内存\n");
  cihptr = (struct ciheader *)mmap(NULL,cihsize,PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1,0);
  memcpy(cihptr,&cihdata,cihsize);
  
  printf("成功加载数据\n");

  printf("当前用户总数: %d\n",cihptr->cih_nusr);
  
  /* 初始化读写锁，静态分配的在开始时就已经初始化 */
  //pthread_rwlock_init(&cihrwlock,NULL);
  return 0;
}


/*
 * 根据IP比较大小，用于二分查找
 */
int
compare(const void *key,const void *q)
{
  return ((struct clientinfo *)key)->ip - ((struct clientinfo *)q)->ip;
}


/*
 * 添加用户信息
 * newci: 新用户信息
 * 返回： 0成功 -1已达用户上限 -2用户已存在
 */
int
addci(const struct clientinfo newci)
{
  int n;
  pthread_rwlock_wrlock(&cihrwlock);
  if(MAXCLIENTS - cihptr->cih_nusr <=0){
    //    printf("已达到最大用户上限\n");
    n = -1;
  }
  else if(bsearch(&newci, &cihptr->cih_clients[MAXCLIENTS - cihptr->cih_nusr],cihptr->cih_nusr,cisize,compare) != NULL){

    //    printf("此用户已存在");
    n = -2;
  } else{
    cihptr->cih_nusr ++ ;
    memcpy( &cihptr->cih_clients[MAXCLIENTS - cihptr->cih_nusr],&newci,cisize);
    
    //    printf("已添加，重新排序\n");
    qsort(&cihptr->cih_clients[MAXCLIENTS - cihptr->cih_nusr],cihptr->cih_nusr,cisize,compare);
    n =	0;
  }
    pthread_rwlock_unlock(&cihrwlock);
    return n;
}


/*
 * 删除用户信息
 * tarci： 目标用户(匹配IP)
 * 返回: 0 成功 -1失败
 */
int
delci(const struct clientinfo tarci)
{
 
  struct clientinfo	*ptr;
  //  printf("删除：申请写锁\n");
  pthread_rwlock_wrlock(&cihrwlock);
  //  printf("删除：取得写锁\n");
  ptr				= (struct clientinfo *)bsearch(&tarci, &cihptr->cih_clients[MAXCLIENTS - cihptr->cih_nusr],cihptr->cih_nusr,cisize,compare);
  if(ptr==NULL){
    //    printf("没有此用户,删除失败\n");
    pthread_rwlock_unlock(&cihrwlock);
    return (-1);
  }
  else{
    //    printf("找到此用户，删除之\n");
    memset(ptr,0,cisize);
    qsort(&cihptr->cih_clients[MAXCLIENTS - cihptr->cih_nusr],cihptr->cih_nusr,cisize,compare);	//将被删除用户移动到最前方(数据为0)
    cihptr->cih_nusr --;
    //    printf("删除：释放写锁\n");
    pthread_rwlock_unlock(&cihrwlock);
    return 0;
  }
}

/*
 * 设置用户信息（匹配IP）。规则： ip从小到大排列。
 * newci: 新任务
 * 返回 0成功 -1失败
 */
int
setci(const struct clientinfo newci)
{
  struct clientinfo	*ptr;
  //  printf("设置：申请写锁\n");
  pthread_rwlock_wrlock(&cihrwlock);
  //  printf("设置：取得写锁\n");  
  ptr				= (struct clientinfo *)bsearch(&newci, &cihptr->cih_clients[MAXCLIENTS - cihptr->cih_nusr],cihptr->cih_nusr,cisize,compare);
  if(ptr==NULL){
    //  printf("没有此用户\n");
     pthread_rwlock_unlock(&cihrwlock);
    return (-1);
  }
  else{
    //    printf("找到此用户，修改之\n");
    memcpy(ptr,&newci,sizeof(struct clientinfo));
    //    printf("设置：释放写锁\n");
    pthread_rwlock_unlock(&cihrwlock);
    return 0;
  }
}

/*
 * 取出用户信息
 * target: 目标用户。如果为空或target.ip==0，则取出全部用户信息，请保证指向ci的内存至少有MAXCLIENTS个struct clientinfo来存放
 * ci: 保存取出的任务
 * 返回： 非负：取出的用户个数， -1失败
 */
int
getci(const struct clientinfo target,struct clientinfo *ci)
{
  //printf("读取：申请读锁\n");
  int			 nmemb;
  struct clientinfo	*ptr;
  pthread_rwlock_rdlock(&cihrwlock);
  if(&target == NULL || target.ip == 0){
    //  printf("取出全部用户信息\n");
    nmemb = cihptr->cih_nusr;
    ptr=&cihptr->cih_clients[MAXCLIENTS - nmemb];
  }
  else{
    ptr = (struct clientinfo *)bsearch(&target, &cihptr->cih_clients[MAXCLIENTS - cihptr->cih_nusr],cihptr->cih_nusr,cisize,compare);
    if(ptr==NULL){
      //    printf("没有找到对应的用户\n");
      nmemb      = 0;
    }else{
      //memcpy(ci,ptr,cisize);//这里有问题，得装到最后一位
      nmemb = 1;
    }
  }
  //printf("nmemb: %d\n",nmemb);
  if(nmemb>0){
    //    memset(ci,0,MAXCLIENTS * cisize);
    memcpy(&ci[MAXCLIENTS - nmemb],ptr,nmemb * cisize);
  }
  
  //printf("取出：释放锁\n");
  pthread_rwlock_unlock(&cihrwlock);
  // printf("取出：已解锁\n");
  return nmemb;
}



/* 关闭用户信息 */
void
closeci()
{
  //  printf("关闭：申请读锁\n");
  pthread_rwlock_rdlock(&cihrwlock);
  //  printf("写入数据到文件\n");
  //printf("fp: %d\n",fp);
  fseek(cihfp,0,SEEK_SET);
  fwrite(cihptr,sizeof(struct ciheader),1,cihfp);
  fclose(cihfp);
  munmap(cihptr,sizeof(struct ciheader));
  //  printf("关闭：释放读锁\n");
  pthread_rwlock_unlock(&cihrwlock);
  pthread_rwlock_destroy(&cihrwlock);
  //printf("成功退出\n");
}
